#include "display_dev.h"

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <xf86drm.h>
#include <xf86drmMode.h>
#include <iostream>
using namespace std;
display_dev::display_dev(string path):
                                                                    fd(-1)                                                                   
{
    int ret = 0, i = 0, j=0;
   
    
    this->connectors.clear();
    this->encoders.clear();
    this->crtcs.clear();    

    this->fd = open(path.c_str(), O_RDWR | O_CLOEXEC);
    if ( this->fd < 0) {
        printf("failed to open card0\n");
        this->fd  = -1;
        return ;
    }

    ret = drmSetClientCap(this->fd, DRM_CLIENT_CAP_ATOMIC, 1);
    if (ret) {
        printf("failed to set client cap atomic\n");
        goto err;
    }
    ret = drmSetClientCap(this->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
    if (ret) {
        printf("failed to set client cap\n");
        goto err;
    }
    printf("成功打开设备\n");
    
    return ;
    err:
        distroy_all();
}


int display_dev::mpp_display_init_element()
{
    int ret = 0, i = 0, j=0;
    drmModeRes* res = NULL;


     /*这边拿到DRM的DRTC(扫描器)，encoders(编码器）connectors(连接器)*/
    res = drmModeGetResources(this->fd);
    if (!res) {
        printf("failed to get r\n");
        goto err;
    }


    //--拿到DRM三大子模块的数量


    
    //this->count_connectors = res->count_connectors;
    printf("连接器数量%d \n",res->count_connectors);
    this->connectors = mpp_element_create_connect(this->fd,res->count_connectors,res->connectors);
    if(this->connectors.size() == 0){
        cout<<"获取连接器失败"<<endl;
        goto err;
    }

    //this->count_encoders = res->count_encoders;
    this->encoders = mpp_element_create_encoder(this->fd,res->count_encoders,res->encoders);
    if(this->encoders.size() == 0){
        cout<<"获取编码器失败"<<endl;
        goto err;
    }

    

    //this->count_crtcs = res->count_crtcs;
    this->crtcs = mpp_element_create_crtc(this->fd, res->count_crtcs,res->crtcs);
    if(this->crtcs.size() == 0){
        cout<<"获取编码器失败"<<endl;
        goto err;
    }

    for (i = 0; i < this->connectors.size() == 0; i++) {

    }

    this->plane = mpp_element_create_plane(this->fd);
    if(this->plane.size() == 0){
        cout<<"获取图层失败"<<endl;
        goto err;
    }
    printf("设备初始化完毕   连接器数量:%d 编码器数量:%d 扫描器数量:%d  图层数量:%d\n", this->connectors.size(),this->encoders.size(),this->crtcs.size(),this->plane.size());


    if(res)
       drmModeFreeResources(res);
    return 0;




    err:
    if(res)
       drmModeFreeResources(res);
    return -1;
}
void display_dev::distroy_all()
{
    printf("销毁各个子模块\n");
    mpp_element_distroy_crtc(this->fd, this->crtcs);  
    mpp_element_distroy_encoder(this->fd,this->encoders);    
    mpp_element_distroy_connect(this->fd,this->connectors);
    mpp_element_distroy_plane(this->fd,this->plane);
      
    if(this->fd > 0){
        close(this->fd);
        this->fd = -1;
    }
        
}
display_dev:: ~display_dev()
{
    distroy_all();
}

int display_dev::mpp_display_dev_get_fd()
{
    return this->fd;
}


vector<drmModeConnectorPtr>  display_dev::mpp_element_create_connect(int fd,uint32_t count_connectors,uint32_t *connectors)
{
      uint32_t i = 0;
      vector<drmModeConnectorPtr> conn;
      conn.clear();
      printf("开始查找连接器\n");
      for (i = 0; i <count_connectors; i++) {     // --拿到所有连接器
         drmModeConnectorPtr  tmp= drmModeGetConnector(fd,connectors[i]);   
         if (!tmp) {
            printf("failed to get connector %d\n", i);
            break;
         }
         printf("找到连接器 ID:%d\n",tmp->connector_id);
         conn.push_back(tmp);
      }
      return conn;
}
void display_dev::mpp_element_distroy_connect(int fd, vector<drmModeConnectorPtr> connector)
{
      if(!connector.empty()){
         for(int i=0;i<connector.size();i++){
            if(connector.at(i))
               drmModeFreeConnector(connector.at(i));
         }
      }
      connector.clear();
}

vector<drmModeEncoderPtr>  display_dev::mpp_element_create_encoder(int fd,uint32_t count_encoders,uint32_t *encoders)
 {
      uint32_t i = 0;
      vector<drmModeEncoderPtr> encoder;
      encoder.clear();
      printf("开始查找编码器\n");
      for (i = 0; i <count_encoders; i++) {     // --拿到所有编码器
      drmModeEncoderPtr  tmp= drmModeGetEncoder(fd,encoders[i]);   
      if (!tmp) {
         printf("failed to get encoder %d\n", i);
         break;
      }
      printf("找到编码器 ID:%d\n",tmp->encoder_id);
      encoder.push_back(tmp);
      }
      return encoder;
 }
void display_dev::mpp_element_distroy_encoder(int fd,vector<drmModeEncoderPtr> encoders)
 {
      if(!encoders.empty()){
         for(int i=0;i<encoders.size();i++){
            if(encoders.at(i))
               drmModeFreeEncoder(encoders.at(i));
         }
      }
      encoders.clear();
 }



int display_dev::get_supported_format(sp_plane* plane, uint32_t* format)
{
    uint32_t i;

    for (i = 0; i < plane->plane->count_formats; i++) {
        if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 || 
            plane->plane->formats[i] == DRM_FORMAT_ARGB8888 || 
            plane->plane->formats[i] == DRM_FORMAT_RGBA8888) {
                *format = plane->plane->formats[i];
            return 0;
        }
    }
    printf("No suitable formats found!\n");
    return -ENOENT;
}
vector<display_dev::sp_plane> display_dev::mpp_element_create_plane(int fd)
{
    vector<display_dev::sp_plane> plane;
    display_dev::sp_plane tmp_plane;
    drmModePlaneRes* pr = NULL;
    plane.clear();
    int ret = 0,j = 0;
    pr = drmModeGetPlaneResources(fd);
    if (!pr) {
        printf("failed to get plane resources\n");
        return plane;
    }
    for (int i = 0; i <  pr->count_planes; i++) {
        tmp_plane.plane = drmModeGetPlane(fd, pr->planes[i]);
        if (!tmp_plane.plane) {
            printf("failed to get plane %d\n", i);
            goto err;
        }
        tmp_plane.bo = NULL;
        tmp_plane.in_use = 0;
        ret = get_supported_format(&tmp_plane, &tmp_plane.format);
        if (ret) {
            printf("failed to get supported format: %d\n", ret);
            goto err;
        }
        for (j = 0; j < this->crtcs.size(); j++) {
            if (tmp_plane.plane->possible_crtcs & (1 << j))
                 this->crtcs.at(j).num_planes++;
            printf("crct index %d ,num_planes %d planes id:%d\n",j,this->crtcs.at(j).num_planes,tmp_plane.plane->plane_id);
        }   //--从这里看每个CRTC下可以有6个图层
        
        plane.push_back(tmp_plane);
    }

    err:
    if (pr)
        drmModeFreePlaneResources(pr);
    return plane;

}

void display_dev::put_sp_plane(sp_plane *plane) 
{
    drmModePlanePtr p;

    /* Get the latest plane information (most notably the crtc_id) */
    p = drmModeGetPlane(fd, plane->plane->plane_id);
    if (p)
        plane->plane = p;

    if (plane->plane->crtc_id)
        drmModeSetPlane(fd, plane->plane->plane_id,
                        plane->plane->crtc_id, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0);
    plane->in_use = 0;
}
void display_dev::mpp_element_distroy_plane(int fd,vector<sp_plane> plane)
{
    int i = 0;
     for (i = 0; i < this->plane.size(); i++) {
            if (this->plane.at(i).in_use)
                put_sp_plane(&this->plane.at(i));
            if (this->plane.at(i).plane)
                drmModeFreePlane(this->plane.at(i).plane);
            //if (plane.at(i).bo)
            //    free_sp_bo(dev->planes[i].bo);
        }
}
 
vector<display_dev::sp_crtc> display_dev::mpp_element_create_crtc(int fd,uint32_t count_crtcs,uint32_t *crtcs)
 {
     uint32_t i = 0;
      vector<display_dev::sp_crtc> crtc;
      display_dev::sp_crtc tmp_crtc;
      crtc.clear();
       printf("开始查找扫描器\n");
      for (i = 0; i <count_crtcs; i++) {     // --拿到所有扫描器
         drmModeCrtcPtr  tmp= drmModeGetCrtc(fd,crtcs[i]);   
         if (!tmp) {
            printf("failed to get encoder %d\n", i);
            break;
         }
         printf("找到扫描器 ID:%d\n",tmp->crtc_id);
        tmp_crtc.crtc = tmp; 
        tmp_crtc.xrgb_scanout = NULL;   
        tmp_crtc.yuvnv12_scanout = NULL;          //--buffer 对象
        tmp_crtc.pipe = i;                       //--这里虚构出pipe
        tmp_crtc.num_planes = 0;          //--记录每个crtc下有多少个图层
        crtc.push_back(tmp_crtc);
      }
      return crtc;

 }
void display_dev::mpp_element_distroy_crtc(int fd,vector<display_dev::sp_crtc>crtc)
 {
    if(!crtc.empty()){
         for(int i=0;i<crtc.size();i++){
            if(crtc.at(i).crtc)
               drmModeFreeCrtc(crtc.at(i).crtc);
         }
      }
      crtc.clear();
    
   // uint32_t i = 0;
   // if (this->crtcs) {
   //    for (i = 0; i < this->num_crtcs; i++) {
   //       if (this->crtcs[i])
   //             drmModeFreeCrtc(this->crtcs[i]);
   //    }
   //    free(this->crtcs);
   //    this->crtcs = NULL;
   // }
   //  mpp_planes_distroy();
 }




vector<drmModeConnectorPtr> display_dev::mpp_dev_get_connectors()
{
    return this->connectors;
}
vector<drmModeEncoderPtr> display_dev::mpp_dev_get_encoders()
{
    return this->encoders;
}
vector<display_dev::sp_crtc>  display_dev::mpp_dev_get_crtcs()
{
    return this->crtcs;
}
vector <display_dev::sp_plane> display_dev::mpp_dev_get_plane()
{
    return this->plane;
}




